package stdx;

import java.io.Closeable;
import java.util.ArrayList;

public abstract class ResPool{
    public static interface Resource extends Closeable{
        public void setPool(ResPool pool);
    }

    class Data{
        private int num = 0;
        private long utime = 0;
        private Boolean idle = true;
        private Resource conn = null;

        void close(){
            if (conn == null) return;
            conn.setPool(null);
            Utils.Close(conn);
            conn = null;
        }
        void release(){
            if (checkSuccess(conn)){
                idle = true;
            }
            else{
                close();
            }
        }
        Closeable get() throws Exception{
            if (conn == null){
                num = 0;
                conn = create();
                conn.setPool(ResPool.this);
            }

            utime = System.currentTimeMillis();
            idle = false;
            ++num;

            return conn;
        }
    }

    int maxlen = 8;
    int timeout = 60;
    ArrayList<Data> vec = new ArrayList<Data>();

    public abstract Resource create() throws Exception;
    public abstract boolean checkSuccess(Closeable conn);

    public void destroy(){
        synchronized(vec){
            for (Data item : vec){
                if (item.idle) item.close();
                item.utime = 0;
            }
        }
    }
    public void setLength(int maxlen){
        this.maxlen = maxlen;
    }
    public void setTimeout(int timeout){
        this.timeout = timeout;
    }
    public void release(Closeable conn){
        synchronized(vec){
            for (Data item : vec){
                if (conn == item.conn){
                    item.release();
                    return;
                }
            }
        }

        Utils.Close(conn);
    }
    public Closeable get() throws Exception{
        long start = System.currentTimeMillis();

        while (true){
            long now = System.currentTimeMillis();

            synchronized(vec){
                Data res = null;

                for (Data item : vec){
                    if (item.idle || item.conn == null){
                        if (item.num < 100 && item.utime + timeout * 1000 > now) return item.get();
                        item.close();
                        res = item;
                    }
                }

                if (res == null){
                    if (vec.size() >= maxlen){
                        if (start + 1000 < System.currentTimeMillis()) throw new Exception("resource busy");
                        Thread.sleep(10);
                        continue;
                    }

                    vec.add(res = new Data());
                }

                return res.get();
            }
        }
    }
}
